/**
 * 所有组件的基类，继承自 cc.Component，
 * 里面封装了一些通用函数
 */

const {ccclass} = cc._decorator;
@ccclass
export class Component<T = any> extends cc.Component {
	/**用来记录组件当前资源的加载路径的字段
	 * 主要用于以下组件：
	 * - cc.Sprite
	 * - cc.ParticleSystem
	 * - sp.Skeleton
	 */
	static assetUrl = Symbol();

	/**此脚本绑定的预制资源的url路径，由代码生成器自动生成 */
	static url = '';

	/**记录第一次传入的data */
	private firstData = null;

	/**用第一次的数据更新表现 */
	refreshUseFirstData() {
		this.setDataEx(this.firstData);
	}

	/**通过数据来改变当前界面ui的表现，或者直接设置脚本某些属性的值
	 * 目前key支持的类型及对应value的类型列表： 8种
	 * - key类型            value类型            改变的内容
	 * - 其他ts原生类型      该类型本身的类型      直接改变这个属性本身 1
	 * - cc.Label           string | number     Label 的 string属性 2
	 * - cc.RichText        string | number     RichText 的 string属性 3
	 * - cc.Sprite          string              Sprite 的 spriteFrame属性 4
	 * - cc.ProgressBar     number              ProgressBar 的 progress属性 5
	 * - cc.Node            boolean | cc.Node   Node 的 active属性 或者直接设置node 6
	 * - cc.ParticleSystem  string              ParticleSystem 的 file 属性 7
	 * - sp.Skeleton        string              sp.Skeleton 的 skeletonData属性 8
	 * @param data 对象类型，key要改变的属性名字 value改变的值，遍历data数据，改变对应显示
	 * @param onFinish 设置完成后的回调函数
	 */
	setDataEx(data: Optional<T>, onFinish?: (err: Error[] | null) => void) {
		this.set(data, this, onFinish);
	}

	/**通过数据来改变当前界面ui的表现，或者直接设置脚本某些属性的值，核心逻辑 */
	private set(data: Optional<T>, context: Component<T>, onFinish?: (err: Error[] | null) => void) {
		//保存第一次的data数据
		if (!this.firstData) {
			this.firstData = data;
		}
		//记录完成的情况，都完成则调用 onFinish 回调
		let i = 0;
		//错误统计数组
		let errorArr: Error[] = [];
		const isFinish = () => {
			i++;
			if (i >= Object.keys(data).length) {
				if (onFinish) {
					let err = null;
					if (errorArr.length > 0) {
						err = errorArr;
						console.error('setData出错!', err);
					}
					onFinish(err);
				}
			}
		};
		for (const key of Object.keys(data)) {
			//data的值
			const value = data[key];
			//当前脚本属性
			const pro = context[key];
			if (typeof pro !== 'undefined') {
				if (
					pro === null ||
					[
						'cc.Label',
						'cc.RichText',
						'cc.Sprite',
						'cc.ProgressBar',
						'cc.Node',
						'cc.ParticleSystem',
						'sp.Skeleton',
					].indexOf(pro.__classname__) === -1
				) {
					//其他ts原生类型
					context[key] = value;
					isFinish();
				} else if (pro.__classname__ === 'cc.Label' || pro.__classname__ === 'cc.RichText') {
					//cc.Label 和 cc.RichText
					(pro as cc.Label | cc.RichText).string = value;
					isFinish();
				} else if (pro.__classname__ === 'cc.Sprite') {
					//cc.Sprite
					//记录当前资源路径
					pro[Component.assetUrl] = value;
					if (value) {
						if (value.indexOf('http') > -1) {
							//远程加载
							GAssets.loadRemote(
								value,
								cc.SpriteFrame,
								(err, res) => {
									if (pro[Component.assetUrl] === value) {
										if (err) {
											console.error('cc.Sprite err', key, value, err.message || err);
											errorArr.push(err);
										} else {
											(pro as cc.Sprite).spriteFrame = res;
										}
									} else {
										console.warn('图片路径切换了');
									}
									isFinish();
								},
								context
							);
						} else {
							//查看是否是调用图集资源
							if (value.indexOf('|') > -1) {
								//图集
								const info = (value as string).split('|');
								GAssets.load(
									info[0],
									cc.SpriteAtlas,
									(err, res) => {
										if (pro[Component.assetUrl] === value) {
											if (err) {
												console.error('cc.SpriteAtlas err', key, value, err.message || err);
												errorArr.push(err);
											} else {
												const sf = res.getSpriteFrame(info[1]);
												if (sf) {
													(pro as cc.Sprite).spriteFrame = sf;
												} else {
													console.error('不存在对应的SpriteFrame', info);
													errorArr.push(new Error('不存在对应的SpriteFrame'));
												}
											}
										} else {
											console.warn('图片路径切换了');
										}
										isFinish();
									},
									context
								);
							} else {
								//普通图片
								GAssets.load(
									value,
									cc.SpriteFrame,
									(err, res) => {
										if (pro[Component.assetUrl] === value) {
											if (err) {
												console.error('cc.Sprite err', key, value, err.message || err);
												errorArr.push(err);
											} else {
												(pro as cc.Sprite).spriteFrame = res;
											}
										} else {
											console.warn('图片路径切换了');
										}
										isFinish();
									},
									context
								);
							}
						}
					} else {
						console.warn('图片路径为空', value);
						(pro as cc.Sprite).spriteFrame = null;
						isFinish();
					}
				} else if (pro.__classname__ === 'cc.ProgressBar') {
					//cc.ProgressBar
					(pro as cc.ProgressBar).progress = value;
					isFinish();
				} else if (pro.__classname__ === 'cc.Node') {
					//cc.Node
					if (typeof value === 'boolean') {
						(pro as cc.Node).active = value;
					} else {
						context[key] = value;
					}
					isFinish();
				} else if (pro.__classname__ === 'cc.ParticleSystem') {
					//cc.ParticleSystem
					//记录当前值
					pro[Component.assetUrl] = value;
					GAssets.load(
						value,
						cc.ParticleAsset,
						(err, res) => {
							if (pro[Component.assetUrl] === value) {
								if (err) {
									console.error('cc.ParticleSystem err', key, value, err.message || err);
									errorArr.push(err);
								} else {
									(pro as cc.ParticleSystem).file = res;
								}
							} else {
								console.warn('cc.ParticleSystem文件路径切换了');
							}
							isFinish();
						},
						context
					);
				} else if (pro.__classname__ === 'sp.Skeleton') {
					//sp.Skeleton
					//记录当前值
					pro[Component.assetUrl] = value;
					if (value) {
						GAssets.load(
							value,
							sp.SkeletonData,
							(err, res) => {
								if (pro[Component.assetUrl] === value) {
									if (err) {
										console.error('sp.Skeleton err', key, value, err.message || err);
										errorArr.push(err);
									} else {
										(pro as sp.Skeleton).skeletonData = res;
									}
								} else {
									console.warn('spine动画路径切换了');
								}
								isFinish();
							},
							context
						);
					} else {
						console.warn('sp.Skeleton动画路径为空', value);
						(pro as sp.Skeleton).skeletonData = null;
						isFinish();
					}
				}
			} else {
				console.error('当前脚本没有该属性', key, value);
			}
		}
	}

	/**setData的异步版本 */
	async setDataAsync(data: Optional<T>) {
		return new Promise<void>((resolve, reject) => {
			this.set(data, this, (err: Error[] | null) => {
				if (err) {
					reject(err);
				} else {
					resolve();
				}
			});
		});
	}

	/**默认销毁的时候移除所有的事件监听 */
	protected onDestroy() {
		 
	}
}
 
